-- __index
prototype = {x = 0, y = 0, width = 100, height = 100}

local mt = {}

function new (o)
	setmetatable(o, mt)
	return o
end

--[[
mt.__index = function (_, key)
	return prototype[key]
end
--]]
mt.__index = prototype

w = new{x = 10, y = 10}
print(w.width) 	-- 100

function setDefault (t, d)
	local mt = {__index = function () return d end}
	setmetatable(t, mt)
end

tab = {x = 10, y = 20}
print(tab.x, tab.z)
setDefault(tab, 0)
print(tab.x, tab.z)

local mt = {__index = function (t) return t.___default end}
function setDefault2 (t, d)
	t.___default = d
	setmetatable(t, mt)
end

-- trace the accessing to table
function track (t)
	local proxy = {}
	local mt = {
		__index = function (_, k)
			print("*access to element " .. tostring(k))
			return t[k]
		end,

		__newindex = function (_, k, v)
			print("*update of element " .. tostring(k) .. " to " .. tostring(v))
			t[k] = v
		end,

		__pairs = function ()
			return function (_, k)
				local nextkey, nextvalue = next(t, k)
				if nextkey ~= nil then
					print("*traversing element " .. tostring(nextkey))
				end
				return nextkey, nextvalue
			end
		end,

		__len = function () return #t end
	}

	setmetatable(proxy, mt)

	return proxy
end

-- read-only table
function readOnly (t)
	local proxy = {}
	local mt = {
		__index = t,
		__newindex = function (t, k, v)
			error("attempt to update a read-only table", 2)
		end
	}

	setmetatable(proxy, mt)

	return proxy
end

days = readOnly{
	"Sunday", 
	"Monday",
	"Tuesday",
	"Wdenesday",
	"Thursday",
	"Friday",
	"Saturday"
}

print(days[1]) 			-- Sunday
days[2] = "Noday" 	-- error
